﻿//------------------------------------------------------------
// AureFramework
// Developed By Drunk Fish
// GitHub: https://github.com/YYYurz
// Gitee: https://gitee.com/yyyurz
//------------------------------------------------------------

using System;
using System.Collections.Generic;
using AureFramework.ReferencePool;
using UnityEngine;

namespace AureFramework.Network
{
	public sealed partial class NetworkModule : AureFrameworkModule, INetworkModule
	{
		private readonly Dictionary<string, NetworkChannel> channelDic = new Dictionary<string, NetworkChannel>();
		private IReferencePoolModule referencePoolModule;
		
		private EventHandler<NetworkConnectedEventArgs> networkConnectedEventHandler;
		private EventHandler<NetworkCloseEventArgs> networkCloseEventHandler;
		private EventHandler<NetworkErrorEventArgs> networkErrorEventHandler;
		private EventHandler<NetworkReceiveEventArgs> networkReceiveEventHandler;
		
		/// <summary>
		/// 模块初始化，只在第一次被获取时调用一次
		/// </summary>
		public override void Init()
		{
			referencePoolModule = Aure.GetModule<IReferencePoolModule>();
			networkConnectedEventHandler = null;
			networkCloseEventHandler = null;
			networkErrorEventHandler = null;
			networkReceiveEventHandler = null;
		}

		/// <summary>
		/// 框架轮询
		/// </summary>
		/// <param name="elapseTime"> 距离上一帧的流逝时间，秒单位 </param>
		/// <param name="realElapseTime"> 距离上一帧的真实流逝时间，秒单位 </param>
		public override void Tick(float elapseTime, float realElapseTime)
		{
			foreach (var channel in channelDic)
			{
				channel.Value.Update();
			}
		}

		/// <summary>
		/// 框架物理轮询
		/// </summary>
		/// <param name="fixedElapseTime"></param>
		/// <param name="realFixedElapseTime"></param>
		public override void FixedTick(float fixedElapseTime, float realFixedElapseTime)
		{
		}
		
		/// <summary>
		/// 框架清理
		/// </summary>
		public override void Clear()
		{
			foreach (var channel in channelDic)
			{
				channel.Value.ShutDown();
			}
			
			channelDic.Clear();
		}

		/// <summary>
		/// 网络连接成功事件
		/// </summary>
		public event EventHandler<NetworkConnectedEventArgs> NetworkConnectedEventHandler
		{
			add
			{
				networkConnectedEventHandler += value;
			}
			remove
			{
				networkConnectedEventHandler -= value;
			}
		}
		
		/// <summary>
		/// 网络连接关闭事件
		/// </summary>
		public event EventHandler<NetworkCloseEventArgs> NetworkCloseEventHandler
		{
			add
			{
				networkCloseEventHandler += value;
			}
			remove
			{
				networkCloseEventHandler -= value;
			}
		}
		
		/// <summary>
		/// 网络错误事件
		/// </summary>
		public event EventHandler<NetworkErrorEventArgs> NetworkErrorEventHandler
		{
			add
			{
				networkErrorEventHandler += value;
			}
			remove
			{
				networkErrorEventHandler -= value;
			}
		}
		
		/// <summary>
		/// 网络收包事件
		/// </summary>
		public event EventHandler<NetworkReceiveEventArgs> NetworkReceiveEventHandler
		{
			add
			{
				networkReceiveEventHandler += value;
			}
			remove
			{
				networkReceiveEventHandler -= value;
			}
		}
		
		/// <summary>
		/// 获取网络频道
		/// </summary>
		/// <param name="channelName"> 网络频道名称 </param>
		/// <returns></returns>
		public INetworkChannel GetNetworkChannel(string channelName)
		{
			if (string.IsNullOrEmpty(channelName))
			{
				Debug.LogError("NetworkModule : Network channel name is invalid.");
				return null;
			}
			
			if (channelDic.TryGetValue(channelName, out var networkChannel))
			{
				return networkChannel;
			}

			return null;
		}

		/// <summary>
		/// 创建网络频道
		/// </summary>
		/// <param name="channelName"> 网络频道名称 </param>
		/// <param name="networkHelper"> 网络频道辅助器 </param>
		/// <returns></returns>
		public INetworkChannel CreateNetworkChannel(string channelName, INetworkHelper networkHelper)
		{
			if (string.IsNullOrEmpty(channelName))
			{
				Debug.LogError("NetworkModule : Network channel name is invalid.");
				return null;
			}

			if (networkHelper == null)
			{
				Debug.LogError("NetworkModule : Network Helper is null.");
				return null;
			}

			if (channelDic.ContainsKey(channelName))
			{
				Debug.LogError($"NetworkModule : Network channel is already exist, name :{channelName}.");
				return null;
			}
			
			var networkChannel = new NetworkChannel(channelName, networkHelper);
			networkChannel.NetworkChannelConnected += OnNetworkChannelConnected;
			networkChannel.NetworkChannelClosed += OnNetworkChannelClosed;
			networkChannel.NetworkChannelError += OnNetworkChannelError;
			networkChannel.NetworkChannelReceive += OnNetworkChannelReceive;
			channelDic.Add(channelName, networkChannel);

			return networkChannel;
		}

		/// <summary>
		/// 销毁网络频道
		/// </summary>
		/// <param name="channelName"> 网络频道名称 </param>
		public void DestroyNetworkChannel(string channelName)
		{
			if (string.IsNullOrEmpty(channelName))
			{
				Debug.LogError("NetworkModule : Network channel name is invalid.");
				return;	
			}
			
			if (channelDic.TryGetValue(channelName, out var channel))
			{
				channel.ShutDown();
				channelDic.Remove(channelName);
			}
		}

		private void OnNetworkChannelConnected(NetworkChannel networkChannel, object userData)
		{
			if (networkConnectedEventHandler == null)
			{
				return;
			}

			lock (networkConnectedEventHandler)
			{
				var networkConnectedEventArgs = NetworkConnectedEventArgs.Create(networkChannel, userData);
				networkConnectedEventHandler.Invoke(this, networkConnectedEventArgs);
				referencePoolModule.Release(networkConnectedEventArgs);
			}
		}

		private void OnNetworkChannelClosed(NetworkChannel networkChannel)
		{
			if (networkCloseEventHandler == null)
			{
				return;
			}

			lock (networkCloseEventHandler)
			{
				var networkCloseEventArgs = NetworkCloseEventArgs.Create(networkChannel);
				networkCloseEventHandler.Invoke(this, networkCloseEventArgs);
				referencePoolModule.Release(networkCloseEventArgs);
			}
		}

		private void OnNetworkChannelError(NetworkChannel networkChannel, string message)
		{
			if (networkErrorEventHandler == null)
			{
				return;
			}

			lock (networkErrorEventHandler)
			{
				var networkCloseEventArgs = NetworkErrorEventArgs.Create(networkChannel, message);
				networkErrorEventHandler.Invoke(this, networkCloseEventArgs);
				referencePoolModule.Release(networkCloseEventArgs);
			}
		}

		private void OnNetworkChannelReceive(NetworkChannel networkChannel, Packet packet)
		{
			if (networkReceiveEventHandler == null)
			{
				return;
			}

			lock (networkReceiveEventHandler)
			{
				var networkReceiveEventArgs = NetworkReceiveEventArgs.Create(networkChannel, packet);
				networkReceiveEventHandler.Invoke(this, networkReceiveEventArgs);
				referencePoolModule.Release(networkReceiveEventArgs);
			}
		}
	}
}